/** \file    mswin/memmap.cpp
  * \brief   Mamery mapping object on a file data
  * \date    2003
  * \author  Fedor Chelnokov
  * \version $Header: /home/cscom1r4/cvsroot/cs/mswin/src/memmap.cpp,v 1.2 2004/05/07 17:37:02 cscom1r4 Exp $
  */

#include "mswin/memmap.h"
#include "throwWin32Error.h"
#include <algorithm>
#include <assert.h>

namespace mswin {

void memmap::open(const char * name, size_t size, int flags)
{
	close();

	DWORD DesiredAccess = GENERIC_READ;
	if (flags & write)
		DesiredAccess |= GENERIC_WRITE;
	DWORD ShareMode = 0;
	if (flags & shared)
		ShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;

	_file = CreateFile(name, DesiredAccess, ShareMode, NULL, // SD
		(flags & open_existing) ? OPEN_EXISTING : CREATE_ALWAYS, // how to create
        FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_ARCHIVE, // file attributes
        NULL // handle to template file
    );

	if (_file == INVALID_HANDLE_VALUE)
		throw Win32Error(std::string("\nas a result of file creation: ") + name);

	if (flags & open_existing)
		size = GetFileSize(_file, 0);

    _map = CreateFileMapping(_file, NULL,
		(flags & write) ? PAGE_READWRITE : PAGE_READONLY, 0, size, NULL);

	if (!_map) {
		CloseHandle(_file);
		throw Win32Error(std::string("\nas a result of file mapping creation: ") + name);
	}

	_base = (char*)MapViewOfFile(_map, (flags & write) ? FILE_MAP_ALL_ACCESS : FILE_MAP_READ,
        0, 0, size);
 
	if (!_base) {
		CloseHandle(_map);
		CloseHandle(_file);
		throw Win32Error(std::string("\nas a result of mapping view of file: ") + name);
	}

	_size = size;
}

void memmap::close()
{
	if (!is_open())
		return;
	UnmapViewOfFile(_base);
	CloseHandle(_map);
	CloseHandle(_file);
}

void memmap::flush()
{
	assert(is_open());
	if (!FlushViewOfFile(_base, _size))
		throwWin32Error("FlushViewOfFile");
}

void memmap::write_str(size_t offset, size_t len, const string & str)
{
	assert(is_open());
	if (str.length() >= len)
		std::copy(str.begin(), str.begin() + len, _base + offset);
	else
		std::fill(
			std::copy(str.begin(), str.begin() + str.length(), _base + offset),
			_base + offset + len, char(0));
}

memmap::string memmap::read_str(size_t offset, size_t len) const
{
	assert(is_open());
	string str(_base + offset, _base + offset + len);
	return str.substr(0, str.find(char(0)));
}

} //namespace mswin
